﻿using AnyCAD.Foundation;
using AnyCAD.NX.ViewModel;

namespace AnyCAD.Primitive.Domain
{
    public class DomainModel : ElementModel
    {
        public GPnt MinPt = new GPnt();
        public GPnt MaxPt = new GPnt(100,100,50);
        public DomainModel()
        {

        }

        public PrimitiveSceneNode CreateNode()
        {
            var geometry = GeometryBuilder.AtomBoxOutline();
            return PrimitiveSceneNode.Create(geometry, null);
        }

        public bool CompuateBBox(Document doc)
        {
            var bbox = new AABox();
            var table = doc.FindTable(nameof(DrawableElement));
            foreach (var id in table.GetIds())
            {
                var drawable = DrawableElement.Cast(doc.FindElement(id));
                if (drawable != null)
                {
                    bbox.merge(drawable.GetWorldBBox());
                }
            }

            if (bbox.isNull())
            {
                return false;
            }

            MinPt = bbox.getMinimum().ToPnt();
            MaxPt = bbox.getMaximum().ToPnt(); 

            return true;
        }

        public UserElement? CreateInstance(Document doc)
        {
            if(!CompuateBBox(doc))          
                return null;

            var scheam = ElementSchemaManager.Instance().FindSchema(nameof(DomainModel));
            var instance = scheam.CreateEntity("空间", doc);
            var component = scheam.AddComponent(instance.GetId(), doc);

            Save(component);

            return UserElement.Cast(instance);
        }

        public static void ShowDomainBox(Document doc)
        {
            var undo = new UndoTransaction(doc);
            undo.Start("Domain");
            var table =  doc.FindTable(nameof(UserElement));
            var instance = UserElement.Cast(table.FindByName("空间"));
            if (instance != null)
            {
                doc.RemoveElement(instance.GetId());
            }
            
            DomainModel model = new DomainModel();                
            instance = model.CreateInstance(doc);
            undo.Commit();
        }
    }


    class DomainSchema : ElementSchema
    {
        public DomainSchema()
                  : base(nameof(DomainModel))
        {
            SetTitle("空间");
            this.SetCategory("Space");
            SetIcon("/OpenCAX.Icons;component/Images/bounding_volume.2l.png");
        }

        public override string OnGetEntityClassName()
        {
            return nameof(UserElement);
        }

        public override ElementModel CreateModel()
        {
            return new DomainModel();
        }
    }


    /// <summary>
    /// 系统提供的适配器，用来自定义显示对象的保存
    /// </summary>
    class DomainInitializer : IUserElementAdaptor
    {
        public string Name { get => nameof(DomainModel); }
        public DomainInitializer()
        {

        }

        public void Show(UserElement element, Document doc, ViewContext vc)
        {
            var component = SchemaComponent.Cast(element.GetComponent(nameof(SchemaComponent)));
            var model = new DomainModel();
            model.Load(component);
            var node = model.CreateNode();
            var p1 = Vector3d.From(model.MinPt);
            var p2 = Vector3d.From(model.MaxPt);

            var center = (p2 - p1) * 0.5;
            var scale = p2 - p1;

            node.SetTransform(Matrix4d.makeTranslation(center) * Matrix4d.makeScale(scale.x, scale.y, scale.z));
            var userId = element.GetId().Value;
            node.SetUserId(userId);
            node.SetPickable(false);
            node.SetVisible(element.GetVisible());
            vc.GetScene().AddNode(node);
            vc.RequestUpdate(EnumUpdateFlags.Scene);
        }

        public void Update(UserElement element, Document doc, ViewContext vc)
        {
            var node = vc.GetScene().FindNodeByUserId(element.GetId().Value);
            if(node != null)
            {
                node.SetVisible(element.GetVisible());

                var component = SchemaComponent.Cast(element.GetComponent(nameof(SchemaComponent)));
                var model = new DomainModel();
                model.Load(component);
                var p1 = Vector3d.From(model.MinPt);
                var p2 = Vector3d.From(model.MaxPt);

                var center = (p2 - p1) * 0.5;
                var scale = p2 - p1;
                node.SetTransform(Matrix4d.makeTranslation(center) * Matrix4d.makeScale(scale.x, scale.y, scale.z));
                
                vc.RequestUpdate(EnumUpdateFlags.Scene);
            }            
        }
    }


}
